/*----------------------------------------------------------------
 * 				Parser
 *
 * Descripcion: clase que se encarga de procesar las instrucciones
 * ingresadas por el usuario.
 * --------------------------------------------------------------*/

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class parser {

	private static boolean complete=false;
	public static List parse(String lista) throws Exception{

		List objs = new LinkedList();
		int cont=0;
		Scanner scn = new Scanner(lista);

		String cache;

		if (!scn.next().equals("(")){
			throw new Exception();
		}
		do{

			cache = scn.next();

			if(!cache.equals(")")){

				if(cache.equals("(")){
					cont++;
					String tmp="( ";

					do{
						tmp = scn.next();
						if(tmp.equals("(")){
						    cont++;
						}
						if(tmp.equals(")")){
						    cont--;
						}
						cache = cache + " " + tmp;
					}while(!tmp.equals(")")|| cont!=0);

					objs.add(parse(cache));

					//objs.add(parse(cache));

				}
				else{

					objs.add(cache);
				}
			}
		}while(!cache.equals(")"));

		return objs;

	}

	public static int operation(ArrayList<String> operator)throws Exception{
	    int ret=0;
	    try{
		ret=(operate(parseOper(operator.remove(operator.size()-1)),operator));
		if(complete){
		    complete=false;
		}else{
		    throw new Exception();
		}
	    }catch(Exception e){throw e;}
	    return ret;
	}
	private static int operate(LinkedList<LinkedList> list, ArrayList<String> operator)throws Exception{
	    char oper;
	    String opera="";
	    Object obj1=new Object();


	    if(list.size()==0){
		throw new Exception();
	    }
	    if(list.size()==1){
		try{
		    obj1=list.get(0);
		    return ((Integer)obj1).intValue();
		}catch(Exception e){throw e;}


	    }else{
		try{

		    opera=operator.remove(0);
		    oper=opera.charAt(0);
		    if(operator.size()==0){
			complete=true;
		    }else{
			complete=false;
		    }
		    int res=0;
		    switch(oper){
			case '+':
			    for (int a=0; a<list.size(); a++){
				res+=(operate(list.get(a), operator));
			    }


			    return res;
			case '*':
			    res=1;
			    for (int a=0; a<list.size(); a++){
				res*=(operate(list.get(a), operator));
			    }


			    return res;
			case '-':
			    if(list.size()==2){
				return operate(list.get(0), operator)-operate(list.get(1), operator);
			    }else{throw new Exception();}
			case '/':
			    if(list.size()==2){
				return operate(list.get(0), operator)/operate(list.get(1), operator);
			    }else{throw new Exception();}
			case '%':
			    if(list.size()==2){
				return operate(list.get(0), operator)/operate(list.get(1), operator);
			    }else{throw new Exception();}
			case 'i':
			    if(list.size()==3){
				boolean check=opBool(list.get(0),operator);
				int pos1=operate(list.get(1),operator);
				int pos2=operate(list.get(2),operator);
				return (check)?pos1:pos2;

			    }else{throw new Exception();}
			case 'c':
			    boolean cond=true;
			    if(opera.equals("cond")){
				for(int a=0; a<list.size(); a++){
				    if(list.get(a).size()==2){
					if(opBool(((LinkedList)(list.get(a).get(0))),operator)&&cond){
					    res=operate(((LinkedList)(list.get(a).get(1))),operator);
					    cond=false;
					}else{
					   operate(((LinkedList)(list.get(a).get(1))),operator);
					}

				    }else{throw new Exception();}
				}
				if(cond){
				    throw new Exception();
				}else{
				    return res;
				}
			    }
			default:
			    if((opera .equals("<="))||(opera .equals("="))||(opera .equals("<"))||(opera .equals(">="))||(opera .equals(">"))||(opera .equals("or"))||(opera .equals("and"))||(opera .equals("not"))){
				operator.add(0,opera);
				res=(opBool(list,operator))?1:0;
				return res;
			    }else{
				throw new Exception();
			    }

		    }
		}catch(Exception e){throw e;}
	    }
	}
	private static LinkedList<LinkedList> parseOper(String lista) throws Exception{

		LinkedList<LinkedList> objs = new LinkedList<LinkedList>();
		int cont=0;
		Scanner scn = new Scanner(lista);

		String cache;

		if (!scn.next().equals("(")){
			throw new Exception();
		}
		do{

			cache = scn.next();

			if(!cache.equals(")")){

				if(cache.equals("(")){
					cont++;
					String tmp="( ";

					do{
						tmp = scn.next();
						if(tmp.equals("(")){
						    cont++;
						}
						if(tmp.equals(")")){
						    cont--;
						}
						cache = cache + " " + tmp;
					}while(!tmp.equals(")")|| cont!=0);

					objs.add(parseOper(cache));

					//objs.add(parse(cache));

				}
				else{
					LinkedList preobj=new LinkedList();
					try{
					    preobj.add(new Integer(Integer.parseInt(cache)));

					    objs.add(preobj);
					}catch(NumberFormatException e){throw new Exception();}
				}
			}
		}while(!cache.equals(")"));

		return objs;

	}
	private static boolean opBool(LinkedList<LinkedList> list, ArrayList<String> operator) throws Exception{
	    char oper;
	    String opera;
	    Object obj1=new Object();


	    if(list.size()==0){
		throw new Exception();
	    }
	    if(list.size()==1){
		try{
		    obj1=list.get(0);
		    if(((String)obj1).toLowerCase().equals("false")){
			return false;
		    }
		    return true;
		}catch(Exception e){System.out.println("ocurrio en opBool");throw e;}


	    }else{
		try{
		    opera=operator.remove(0);
		    oper=opera.charAt(0);
		    if(operator.size()==0){
			complete=true;
		    }else{
			complete=false;
		    }
		    boolean res=false;
		    switch(oper){
			case 'o':
			    for (int a=0; a<list.size(); a++){
				res=(opBool(list.get(a), operator))||res;
			    }


			    return res;
			case 'a':
			    res=true;
			    for (int a=0; a<list.size(); a++){
				res=(opBool(list.get(a), operator))&&res;
			    }


			    return res;

			case 'n':
			    if(list.size()==2){
				res= !(opBool(list.get(1), operator));
				return res;
			    }else{throw new Exception();}
			case '=':
			    if(list.size()==2){
				res= (operate(list.get(0), operator)==operate(list.get(1), operator));
				return res;
			    }else{throw new Exception();}
			case '/':
			    if(list.size()==2){
				res= (operate(list.get(0), operator)!=operate(list.get(1), operator));
				return res;
			    }else{throw new Exception();}
			case '<':
			    if(list.size()==2){
				if(opera.length()==2){
				    res=(operate(list.get(0), operator)<=operate(list.get(1), operator));
				    return res;
				}
				else{
				    res=(operate(list.get(0), operator)<operate(list.get(1), operator));
				    return res;
				}
			    }else{throw new Exception();}
			    case '>':
			    if(list.size()==2){
				if(opera.length()==2){
				    res=(operate(list.get(0), operator)>=operate(list.get(1), operator));
				    return res;
				}
				else{
				    res=(operate(list.get(0), operator)>operate(list.get(1), operator));
				    return res;
				}
			    }else{throw new Exception();}
			default:
			    throw new Exception();

		    }
		}catch(Exception e){throw e;}
	    }


	}
}

